#include "Debug.hpp"
#include "Configuration.hpp"

#include <unistd.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <errno.h>

#include <stdio.h>

int main() {
    DEBUG_PRINT("applicient Search Engine Client starts running.");

    struct sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_addr.s_addr = ::inet_addr(CONFIGURATION("IP", std::string).c_str());
    serverAddress.sin_port = ::htons(CONFIGURATION("Port", unsigned short));

    int socketFileDescriptor = ::socket(AF_INET, SOCK_STREAM, 0);
    if (::connect(socketFileDescriptor, (struct sockaddr *)&serverAddress, sizeof serverAddress)) {
        ::perror("connect");
        ::close(socketFileDescriptor);
        return -1;
    }
    DEBUG_PRINT("connect success.");
    
    int epollFileDescriptor = ::epoll_create1(0);
    struct epoll_event epollEvent, epollEvents[10];
    epollEvent.data.fd = socketFileDescriptor;
    epollEvent.events = EPOLLIN;
    ::epoll_ctl(epollFileDescriptor, EPOLL_CTL_ADD, socketFileDescriptor, &epollEvent);
    DEBUG_PRINT("add socket file descriptor to epoll success.");
    epollEvent.data.fd = STDIN_FILENO;
    ::epoll_ctl(epollFileDescriptor, EPOLL_CTL_ADD, STDIN_FILENO, &epollEvent);
    DEBUG_PRINT("add stdin file descriptor to epoll success.");

    char *buffer = new char[1024];
    int readLength = 0;
    while (1) {
        int readyCount = ::epoll_wait(epollFileDescriptor, epollEvents, sizeof epollEvents / sizeof epollEvents[0], 5000);
        // DEBUG_PRINT("readyCount = %d.\n", readyCount);
        if (readyCount == -1 && errno == EINTR) {
            continue;
        } else if (readyCount == -1) {
            ::perror("epoll_wait");
            break;
        } else if (readyCount == 0) {
            // DEBUG_PRINT("timeout.\n");
        } else {
            for (int i = 0; i < readyCount; i++) {
                if (epollEvents[i].data.fd == socketFileDescriptor) {
                    readLength = ::read(socketFileDescriptor, buffer, 1024 - 1);
                    if (readLength == 0) {
                        ::printf("disconnect.\n");
                        goto LabelExit;
                    }
                    buffer[readLength] = 0;
                    ::puts(buffer);
                } else if (epollEvents[i].data.fd == STDIN_FILENO) {
                    readLength = ::read(STDIN_FILENO, buffer, 1024 - 1);
                    ::write(socketFileDescriptor, buffer, readLength - 1);
                }
            }
        }
    }

LabelExit:
    delete[] buffer;
    ::close(epollFileDescriptor);
    ::close(socketFileDescriptor);
    return 0;
    return 0;
}